home *** CD-ROM | disk | FTP | other *** search
/ ADA Programming Guide / ADA Programming Guide.iso / ada_gnu / adainc / s-valrea.adb < prev    next >
Text File  |  1996-01-30  |  10KB  |  323 lines

  1. ------------------------------------------------------------------------------
  2. --                                                                          --
  3. --                         GNAT COMPILER COMPONENTS                         --
  4. --                                                                          --
  5. --                      S Y S T E M . V A L _ R E A L                       --
  6. --                                                                          --
  7. --                                 S p e c                                  --
  8. --                                                                          --
  9. --                            $Revision: 1.6 $                              --
  10. --                                                                          --
  11. --           Copyright (c) 1992,1993,1994 NYU, All Rights Reserved          --
  12. --                                                                          --
  13. -- The GNAT library is free software; you can redistribute it and/or modify --
  14. -- it under terms of the GNU Library General Public License as published by --
  15. -- the Free Software  Foundation; either version 2, or (at your option) any --
  16. -- later version.  The GNAT library is distributed in the hope that it will --
  17. -- be useful, but WITHOUT ANY WARRANTY;  without even  the implied warranty --
  18. -- of MERCHANTABILITY  or  FITNESS FOR  A PARTICULAR PURPOSE.  See the  GNU --
  19. -- Library  General  Public  License for  more  details.  You  should  have --
  20. -- received  a copy of the GNU  Library  General Public License  along with --
  21. -- the GNAT library;  see the file  COPYING.LIB.  If not, write to the Free --
  22. -- Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.        --
  23. --                                                                          --
  24. ------------------------------------------------------------------------------
  25.  
  26. with System.Powten_Table; use System.Powten_Table;
  27. with System.Val_Util;     use System.Val_Util;
  28.  
  29. package body System.Val_Real is
  30.  
  31.    ---------------
  32.    -- Scan_Real --
  33.    ---------------
  34.  
  35.    function Scan_Real
  36.      (Str  : String;
  37.       Ptr  : access Positive'Base;
  38.       Max  : Positive'Base)
  39.       return Long_Long_Float
  40.    is
  41.       P : Positive'Base;
  42.       --  Local copy of string pointer
  43.  
  44.       Base   : Long_Long_Float;
  45.       --  Base value
  46.  
  47.       Uval : Long_Long_Float;
  48.       --  Accumulated float result
  49.  
  50.       subtype Digs is Character range '0' .. '9';
  51.       --  Used to check for decimal digit
  52.  
  53.       Scale : Integer := 0;
  54.       --  Power of Base to multiply result by
  55.  
  56.       Start : Positive;
  57.       --  Position of starting non-blank character
  58.  
  59.       Minus : Boolean;
  60.       --  Set to True if minus sign is present, otherwise to False
  61.  
  62.       Bad_Base : Boolean := False;
  63.       --  Set True if Base out of range or if out of range digit
  64.  
  65.       After_Point : Natural := 0;
  66.       --  Set to 1 after the point
  67.  
  68.       procedure Scanf;
  69.       --  Scans integer literal value starting at current character position.
  70.       --  For each digit encountered, Uval is multiplied by 10.0, and the new
  71.       --  digit value is incremented. In addition Scale is decremented for each
  72.       --  digit encountered if we are after the point (After_Point = 1). The
  73.       --  longest possible syntactically valid numeral is scanned out, and on
  74.       --  return P points past the last character. On entry, the current
  75.       --  character is known to be a digit, so a numeral is definitely present.
  76.  
  77.       procedure Scanf is
  78.          Digit : Natural;
  79.  
  80.       begin
  81.          loop
  82.             Digit := Character'Pos (Str (P)) - Character'Pos ('0');
  83.             Uval := Uval * 10.0 + Long_Long_Float (Digit);
  84.             P := P + 1;
  85.             Scale := Scale - After_Point;
  86.  
  87.             --  Done if end of input field
  88.  
  89.             if P > Max then
  90.                return;
  91.  
  92.             --  Non-digit encountered
  93.  
  94.             elsif Str (P) not in Digs then
  95.  
  96.                --  If syntactically valid underline, just skip it
  97.  
  98.                if Str (P) = '_'
  99.                  and then P < Max
  100.                  and then Str (P + 1) in Digs
  101.                then
  102.                   P := P + 1;
  103.  
  104.                --  If any other non-digit, return
  105.  
  106.                else
  107.                   return;
  108.                end if;
  109.             end if;
  110.          end loop;
  111.       end Scanf;
  112.  
  113.    --  Start of processing for System.Scan_Real
  114.  
  115.    begin
  116.       Scan_Sign (Str, Ptr, Max, Minus, Start);
  117.       P := Ptr.all;
  118.       Ptr.all := Start;
  119.  
  120.       --  If digit, scan numeral before point
  121.  
  122.       if Str (P) in Digs then
  123.          Uval := 0.0;
  124.          Scanf;
  125.  
  126.       --  Initial point, allowed only if followed by digit (RM 3.5(47))
  127.  
  128.       elsif Str (P) = '.'
  129.         and then P < Max
  130.         and then Str (P + 1) in Digs
  131.       then
  132.          Uval := 0.0;
  133.  
  134.       --  Any other initial character is an error
  135.  
  136.       else
  137.          raise Constraint_Error;
  138.       end if;
  139.  
  140.       --  Deal with based case
  141.  
  142.       if P < Max and then (Str (P) = ':' or else Str (P) = '#') then
  143.          declare
  144.             Base_Char : constant Character := Str (P);
  145.             Digit     : Natural;
  146.             Fdigit    : Long_Long_Float;
  147.  
  148.          begin
  149.             if Uval < 2.0 or else Uval > 16.0 then
  150.                Bad_Base := True;
  151.             end if;
  152.  
  153.             Base := Uval;
  154.             Uval := 0.0;
  155.             P := P + 1;
  156.  
  157.             --  Special check to allow initial point (RM 3.5(49))
  158.  
  159.             if Str (P) = '.' then
  160.                After_Point := 1;
  161.                P := P + 1;
  162.             end if;
  163.  
  164.             --  Loop to scan digits of based number. On entry to the loop we
  165.             --  must have a valid digit. If we don't, then we have an illegal
  166.             --  floating-point value, and we raise Constraint_Error, note that
  167.             --  Ptr at this stage was reset to the proper (Start) value.
  168.  
  169.             loop
  170.                if P > Max then
  171.                   raise Constraint_Error;
  172.  
  173.                elsif Str (P) in Digs then
  174.                   Digit := Character'Pos (Str (P)) - Character'Pos ('0');
  175.  
  176.                elsif Str (P) in 'A' .. 'F' then
  177.                   Digit :=
  178.                     Character'Pos (Str (P)) - (Character'Pos ('A') - 10);
  179.  
  180.                elsif Str (P) in 'a' .. 'f' then
  181.                   Digit :=
  182.                     Character'Pos (Str (P)) - (Character'Pos ('a') - 10);
  183.  
  184.                else
  185.                   raise Constraint_Error;
  186.                end if;
  187.  
  188.                P := P + 1;
  189.                Fdigit := Long_Long_Float (Digit);
  190.  
  191.                if Fdigit >= Base then
  192.                   Bad_Base := True;
  193.                else
  194.                   Scale := Scale - After_Point;
  195.                   Uval := Uval * Base + Fdigit;
  196.                end if;
  197.  
  198.                --  Error if no base character after digit scanned
  199.  
  200.                if P > Max then
  201.                   raise Constraint_Error;
  202.  
  203.                --  Just skip past underline (we will require digit after it)
  204.  
  205.                elsif Str (P) = '_' then
  206.                   P := P + 1;
  207.  
  208.                else
  209.                   --  Skip past period after digit. Note that the processing
  210.                   --  here will permit either a digit after the period, or the
  211.                   --  terminating base character, as allowed in (RM 3.5(48))
  212.  
  213.                   if Str (P) = '.' and then After_Point = 0 then
  214.                      P := P + 1;
  215.                      After_Point := 1;
  216.  
  217.                      if P > Max then
  218.                         raise Constraint_Error;
  219.                      end if;
  220.                   end if;
  221.  
  222.                   --  Terminating base character is recognized only if it
  223.                   --  appears after a point, otherwise it is illegal
  224.  
  225.                   exit when Str (P) = Base_Char and then After_Point = 1;
  226.                end if;
  227.             end loop;
  228.  
  229.             --  Based number successfully scanned out (point was found)
  230.  
  231.             Ptr.all := P + 1;
  232.          end;
  233.  
  234.       --  Non-based case, we must be at a point now
  235.  
  236.       else
  237.          if Str (P) /= '.' then
  238.             raise Constraint_Error;
  239.  
  240.          else
  241.             Base := 10.0;
  242.             After_Point := 1;
  243.             P := P + 1;
  244.  
  245.             --  Scan digits after point if any are present (RM 3.5(46))
  246.  
  247.             if P <= Max and then Str (P) in Digs then
  248.                Scanf;
  249.             end if;
  250.  
  251.             Ptr.all := P;
  252.          end if;
  253.       end if;
  254.  
  255.       --  At this point, we have Uval containing the digits of the value as
  256.       --  an integer, and Scale indicates the negative of the number of digits
  257.       --  after the point. Base contains the base value (an integral value in
  258.       --  the range 2.0 .. 16.0). Test for exponent, must be at least one
  259.       --  character after the E for the exponent to be valid.
  260.  
  261.       Scale := Scale + Scan_Exponent (Str, Ptr, Max, Real => True);
  262.  
  263.       --  At this point the exponent has been scanned if one is present and
  264.       --  Scale is adjusted to include the exponent value. Uval contains the
  265.       --  the integral value which is to be multiplied by Base ** Scale.
  266.  
  267.       --  If base is not 10, use exponentiation for scaling
  268.  
  269.       if Base /= 10.0 then
  270.          Uval := Uval * Base ** Scale;
  271.  
  272.       --  For base 10, use power of ten table if in range
  273.  
  274.       elsif Scale > 0 then
  275.          if Scale > Powten'Length then
  276.             Uval := Uval * 10.0 ** Scale;
  277.          else
  278.             Uval := Uval * Powten (Scale);
  279.          end if;
  280.  
  281.       elsif Scale < 0 then
  282.          if (-Scale) > Powten'Length then
  283.             Uval := Uval * 10.0 ** Scale;
  284.          else
  285.             Uval := Uval / Powten (-Scale);
  286.          end if;
  287.       end if;
  288.  
  289.       --  Here is where we check for a bad based number
  290.  
  291.       if Bad_Base then
  292.          raise Constraint_Error;
  293.  
  294.       --  If OK, then deal with initial minus sign, note that this processing
  295.       --  is done even if Uval is zero, so that -0.0 is correctly interpreted.
  296.  
  297.       else
  298.          if Minus then
  299.             return -Uval;
  300.          else
  301.             return Uval;
  302.          end if;
  303.       end if;
  304.  
  305.    end Scan_Real;
  306.  
  307.    ----------------
  308.    -- Value_Real --
  309.    ----------------
  310.  
  311.    function Value_Real (Str : String) return Long_Long_Float is
  312.       V : Long_Long_Float;
  313.       P : aliased Natural := Str'First;
  314.  
  315.    begin
  316.       V := Scan_Real (Str, P'Access, Str'Last);
  317.       Scan_Trailing_Blanks (Str, P);
  318.       return V;
  319.  
  320.    end Value_Real;
  321.  
  322. end System.Val_Real;
  323.